package cn.silver.module.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.silver.framework.core.constant.Constants;
import cn.silver.framework.core.constant.UserConstants;
import cn.silver.framework.core.enums.SystemStatusEnums;
import cn.silver.framework.core.exception.AuthException;
import cn.silver.framework.core.exception.ServiceException;
import cn.silver.framework.core.utils.StringUtils;
import cn.silver.framework.mybatis.domain.TreeEntity;
import cn.silver.framework.mybatis.service.impl.TreeServiceImpl;
import cn.silver.framework.openapi.constant.ResultEnum;
import cn.silver.framework.satoken.model.LoginUser;
import cn.silver.framework.satoken.utils.LoginHelper;
import cn.silver.module.authority.bean.RoleBean;
import cn.silver.module.authority.domain.SysRole;
import cn.silver.module.authority.domain.SysRoleMenu;
import cn.silver.module.authority.mapper.SysRoleMenuMapper;
import cn.silver.module.authority.service.ISysRoleService;
import cn.silver.module.authority.service.ISysTenantGroupService;
import cn.silver.module.system.bean.MenuBean;
import cn.silver.module.system.domain.SysMenu;
import cn.silver.module.system.enums.MenuTypeEnums;
import cn.silver.framework.mybatis.enums.RoleTypeEnums;
import cn.silver.module.system.mapper.SysMenuMapper;
import cn.silver.module.system.model.MetaModel;
import cn.silver.module.system.model.RouterModel;
import cn.silver.module.system.param.MenuParam;
import cn.silver.module.system.service.ISysMenuService;
import cn.silver.module.system.service.ISysUserRoleService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 菜单 业务层处理
 *
 * @author Silver Zhou
 */
@Service
@RequiredArgsConstructor
public class SysMenuServiceImpl extends TreeServiceImpl<SysMenuMapper, SysMenu, MenuParam, MenuBean> implements ISysMenuService {

    private final ISysRoleService roleService;
    private final ISysUserRoleService userRoleService;
    private final SysRoleMenuMapper roleMenuMapper;
    private final ISysTenantGroupService groupService;

    /**
     * 根据用户ID查询菜单
     *
     * @return 菜单列表
     */
    @Override
    public List<RouterModel> selectLocalRouter() {
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (loginUser == null) {
            throw new AuthException("登录信息不存在，请重新登录", ResultEnum.UNAUTHORIZED.getCode());
        }
        List<MenuBean> menus;
        LambdaQueryWrapper<SysMenu> wrapper = Wrappers.lambdaQuery();
        wrapper.in(SysMenu::getType, MenuTypeEnums.MENU_GROUP.getCode(), MenuTypeEnums.MENU_ITEM.getCode())
                .eq(SysMenu::getStatus, SystemStatusEnums.NORMAL.getCode()).orderByAsc(SysMenu::getPid).orderByAsc(SysMenu::getSort);
        if (!LoginHelper.isSuperAdmin()) {
            String roleId = loginUser.getRole() != null ? loginUser.getRole().getId() : null;
            if (StringUtils.isBlank(roleId)) {
                RoleBean bean = this.roleService.selectOne(new LambdaQueryWrapper<SysRole>().eq(SysRole::getType, RoleTypeEnums.COMMON_ROLE.getCode()));
                roleId = bean != null ? bean.getId() : null;
            }
            wrapper.exists("select 1 from sys_role_menu rm where rm.menu_id = sys_menu.id and rm.role_id = {0}", roleId);
        }
        menus = this.baseMapper.selectVoList(wrapper);
        Map<String, List<MenuBean>> menuMap = menus.stream().collect(Collectors.groupingBy(MenuBean::getPid));
        menus.stream().filter(item -> menuMap.containsKey(item.getId())).forEach(item -> {
            List<MenuBean> beans = menuMap.get(item.getId());
            beans.forEach(child -> child.setParent(item));
            if (item.getType().equalsIgnoreCase(MenuTypeEnums.MENU_ITEM.getCode())) {
                item.getParent().addChildren(beans);
            } else {
                item.addChildren(beans);
            }
        });
        return this.buildMenus(menus.stream().filter(item -> TreeEntity.ROOT_NODE.equalsIgnoreCase(item.getPid())).toList());
    }

    /**
     * 根据用户ID查询权限
     *
     * @param userId 用户ID
     * @return 权限列表
     */
    @Override
    public Set<String> selectLocalPermission(String userId) {
        Set<String> permsSet = new HashSet<>();
        List<RoleBean> roles = this.userRoleService.selectRoleGroup(userId);
        List<String> permissions = roles.stream().map(RoleBean::getType).toList();
        if (permissions.contains(RoleTypeEnums.SUPER_ROLE.getCode())) {
            permsSet.add(Constants.ALL_PERMISSION);
        } else {
            List<String> perms = baseMapper.selectMenuPermsByRoleId(userId);
            for (String perm : perms) {
                if (StringUtils.isNotEmpty(perm)) {
                    permsSet.addAll(StringUtils.splitList(perm.trim()));
                }
            }
        }
        return permsSet;
    }

    /**
     * 构建前端路由所需要的菜单
     *
     * @param menus 菜单列表
     * @return 路由列表
     */
    public List<RouterModel> buildMenus(List<MenuBean> menus) {
        List<RouterModel> routers = new LinkedList<>();
        for (MenuBean menu : menus) {
            RouterModel router = new RouterModel();
            router.setHidden(!menu.getVisible());
            router.setName(menu.getRouteName());
            router.setPath(menu.getRouterPath());
            router.setComponent(menu.getComponentInfo());
            router.setQuery(menu.getParam());
            MenuBean parant = menu.getParent();
            if (parant != null && MenuTypeEnums.MENU_ITEM.getCode().equalsIgnoreCase(parant.getType())) {
                router.setMeta(new MetaModel(menu.getName(), menu.getIcon(), menu.getCache(), menu.getUrl(),
                        "/" + parant.getParent().getUrl() + "/" + parant.getUrl()));
            } else {
                router.setMeta(new MetaModel(menu.getName(), menu.getIcon(), menu.getCache(), menu.getUrl()));
            }
            List<MenuBean> cMenus = menu.getChildren();
            if (CollUtil.isNotEmpty(cMenus)) {
                router.setAlwaysShow(true);
                router.setRedirect("noRedirect");
                router.setChildren(buildMenus(cMenus));
            } else if (menu.isMenuFrame()) {
                List<RouterModel> childrenList = new ArrayList<>();
                RouterModel children = new RouterModel();
                children.setPath(menu.getPath());
                children.setComponent(menu.getComponent());
                children.setName(StringUtils.capitalize(menu.getPath()));
                children.setMeta(new MetaModel(menu.getName(), menu.getIcon(), menu.getCache(), menu.getPath()));
                children.setQuery(menu.getParam());
                childrenList.add(children);
                router.setChildren(childrenList);
            } else if (menu.getPid().equalsIgnoreCase(TreeEntity.ROOT_NODE) && menu.isInnerLink()) {
                router.setMeta(new MetaModel(menu.getName(), menu.getIcon()));
                router.setPath("/");
                List<RouterModel> childrenList = new ArrayList<>();
                RouterModel children = new RouterModel();
                String routerPath = MenuBean.innerLinkReplaceEach(menu.getPath());
                children.setPath(routerPath);
                children.setComponent(UserConstants.INNER_LINK);
                children.setName(StringUtils.capitalize(routerPath));
                children.setMeta(new MetaModel(menu.getName(), menu.getIcon(), menu.getPath()));
                childrenList.add(children);
                router.setChildren(childrenList);
            }
            routers.add(router);
        }
        return routers;
    }

    /**
     * 是否存在菜单子节点
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    public boolean hasChildByMenuId(String menuId) {
        return baseMapper.exists(new LambdaQueryWrapper<SysMenu>().eq(SysMenu::getPid, menuId));
    }

    /**
     * 查询菜单使用数量
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    public boolean checkMenuExistRole(String menuId) {
        return roleMenuMapper.exists(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getMenuId, menuId));
    }

    /**
     * 删除菜单管理信息
     *
     * @param id 菜单ID
     * @return 结果
     */
    @Override
    public boolean delete(String id) {
        if (this.hasChildByMenuId(id)) {
            throw new ServiceException("存在子菜单,不允许删除");
        }
        if (this.checkMenuExistRole(id)) {
            throw new ServiceException("菜单已分配,不允许删除");
        }
        return SqlHelper.retBool(baseMapper.deleteById(id));
    }

}
